#include "cw2015.h"
#include "driver/i2c.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define I2C_MASTER_NUM I2C_NUM_0
#define I2C_TIMEOUT_MS 1000

static const char *TAG = "CW2015";

// 全局变量
static cw_battery_t cw_bat;
static uint8_t if_quickstart = 0;
static uint8_t reset_loop = 0;
static uint32_t allow_no_charger_full = 0;
static uint32_t allow_charger_always_zero = 0;
static uint8_t no_charger_full_jump = 0;

// 电池建模信息
static const unsigned char cw_bat_config_info[SIZE_BATINFO] = {
    0X15,0X7E,0X7C,0X5C,0X64,0X6A,0X65,0X5C,0X55,0X53,0X56,0X61,0X6F,0X66,0X50,0X48,
    0X43,0X42,0X40,0X43,0X4B,0X5F,0X75,0X7D,0X52,0X44,0X07,0XAE,0X11,0X22,0X40,0X56,
    0X6C,0X7C,0X85,0X86,0X3D,0X19,0X8D,0X1B,0X06,0X34,0X46,0X79,0X8D,0X90,0X90,0X46,
    0X67,0X80,0X97,0XAF,0X80,0X9F,0XAE,0XCB,0X2F,0X00,0X64,0XA5,0XB5,0X11,0XD0,0X11
};

// 内部函数声明
static esp_err_t cw2015_read_bytes(uint8_t reg_addr, uint8_t *data, size_t len);
static esp_err_t cw2015_write_bytes(uint8_t reg_addr, uint8_t *data, size_t len);
static esp_err_t cw2015_update_config_info(void);

// I2C读取函数
static esp_err_t cw2015_read_bytes(uint8_t reg_addr, uint8_t *data, size_t len)
{
    esp_err_t ret;
    
    // 第一步：写入寄存器地址
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (CW2015_ADDR << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd, reg_addr, true);
    i2c_master_stop(cmd);
    ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, I2C_TIMEOUT_MS / portTICK_PERIOD_MS);
    i2c_cmd_link_delete(cmd);
    
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "写入寄存器地址失败: 0x%02X", reg_addr);
        return ret;
    }
    
    // 短暂延时
    vTaskDelay(pdMS_TO_TICKS(1));
    
    // 第二步：读取数据
    cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (CW2015_ADDR << 1) | I2C_MASTER_READ, true);
    if (len > 1) {
        i2c_master_read(cmd, data, len - 1, I2C_MASTER_ACK);
    }
    i2c_master_read_byte(cmd, data + len - 1, I2C_MASTER_NACK);
    i2c_master_stop(cmd);
    ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, I2C_TIMEOUT_MS / portTICK_PERIOD_MS);
    i2c_cmd_link_delete(cmd);
    
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "读取数据失败: 0x%02X", reg_addr);
    }
    
    return ret;
}

// I2C写入函数
static esp_err_t cw2015_write_bytes(uint8_t reg_addr, uint8_t *data, size_t len)
{
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (CW2015_ADDR << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd, reg_addr, true);
    i2c_master_write(cmd, data, len, true);
    i2c_master_stop(cmd);
    
    esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, I2C_TIMEOUT_MS / portTICK_PERIOD_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}

// 电池建模信息写入函数（内部使用）
static esp_err_t cw2015_write_bat_model(void)
{
    ESP_LOGI(TAG, "开始写入电池建模信息...");
    
    // 写入电池建模信息
    for (int i = 0; i < SIZE_BATINFO; i++) {
        esp_err_t ret = cw2015_write_bytes(REG_BATINFO + i, (uint8_t*)&cw_bat_config_info[i], 1);
        if (ret != ESP_OK) {
            ESP_LOGE(TAG, "写入电池建模信息失败，位置: 0x%02X", REG_BATINFO + i);
            return ret;
        }
    }
    
    ESP_LOGI(TAG, "电池建模信息写入完成");
    return ESP_OK;
}

// 获取电池电压，增加多次采样平均
esp_err_t cw2015_get_voltage(float *voltage)
{
    uint8_t ret;
    uint8_t reg_val[2];
    uint32_t ad_value = 0;
    uint32_t ad_buff = 0;
    uint32_t ad_value_min = 0;
    uint32_t ad_value_max = 0;
    
    // 采样3次取平均值
    for(int i = 0; i < 3; i++) {
        ret = cw2015_read_bytes(REG_VCELL, reg_val, 2);
        if (ret != ESP_OK) {
            return ret;
        }
        
        ad_buff = (reg_val[0] << 8) + reg_val[1];
        
        if(i == 0) {
            ad_value_min = ad_buff;
            ad_value_max = ad_buff;
        }
        if(ad_buff < ad_value_min) {
            ad_value_min = ad_buff;
        }
        if(ad_buff > ad_value_max) {
            ad_value_max = ad_buff;
        }
        ad_value += ad_buff;
    }
    
    // 去掉最大值和最小值后的平均值
    ad_value -= ad_value_min;
    ad_value -= ad_value_max;
    *voltage = ad_value * 0.305; // 305uV分辨率
    
    return ESP_OK;
}

// 获取电池容量，增加容量跳变保护
esp_err_t cw2015_get_soc(float *soc)
{
    uint8_t reg_val[2];
    esp_err_t ret = cw2015_read_bytes(REG_SOC, reg_val, 2);
    if (ret != ESP_OK) {
        return ret;
    }
    
    float new_soc = reg_val[0] + (reg_val[1] / 256.0);
    
    // 容量跳变保护
    if (new_soc > 100.0f) {
        new_soc = 100.0f;
    } else if (new_soc < 0.0f) {
        new_soc = 0.0f;
    }
    
    // 充电状态下的容量保护
    if (cw_bat.usb_online) {
        if (new_soc >= 95.0f && new_soc <= cw_bat.capacity) {
            allow_no_charger_full++;
            if (allow_no_charger_full >= BATTERY_UP_MAX_CHANGE) {
                new_soc = cw_bat.capacity + 1;
                if (new_soc > 100.0f) new_soc = 100.0f;
                no_charger_full_jump = 1;
                allow_no_charger_full = 0;
            }
        }
    }
    
    *soc = new_soc;
    cw_bat.capacity = new_soc;
    
    return ESP_OK;
}

// 获取剩余运行时间（分钟）
esp_err_t cw2015_get_remaining_time(uint16_t *minutes)
{
    uint8_t data[2];
    esp_err_t ret = cw2015_read_bytes(REG_RRT_ALERT, data, 2);
    if (ret != ESP_OK) {
        return ret;
    }
    
    // 计算剩余时间
    uint16_t rrt = ((data[0] & 0x1F) << 8) | data[1];
    
    // 根据电池容量和电压计算更准确的剩余时间
    if (rrt == 8191 || rrt == 0) {
        float voltage, soc;
        
        // 获取当前电压和电量
        ret = cw2015_get_voltage(&voltage);
        if (ret != ESP_OK) {
            return ret;
        }
        
        ret = cw2015_get_soc(&soc);
        if (ret != ESP_OK) {
            return ret;
        }
        
        // 估算剩余时间
        // 假设平均功耗为500mA（这个值需要根据实际使用情况调整）
        float remaining_capacity = 3000.0f * (soc / 100.0f); // mAh
        *minutes = (uint16_t)((remaining_capacity / 500.0f) * 60.0f);
        
        ESP_LOGD(TAG, "使用估算值计算剩余时间: %d分钟", *minutes);
    } else {
        *minutes = rrt;
    }
    
    // 合理性检查
    if (*minutes > 24*60) { // 超过24小时的值可能不准确
        *minutes = (uint16_t)((cw_bat.capacity * 3000.0f / 100.0f / 500.0f) * 60.0f);
        ESP_LOGW(TAG, "剩余时间值异常，使用估算值: %d分钟", *minutes);
    }
    
    return ESP_OK;
}

// 设置警报阈值
esp_err_t cw2015_set_alert_threshold(uint8_t percent)
{
    if (percent > 31) {
        return ESP_ERR_INVALID_ARG;
    }
    
    uint8_t config = percent << 3;
    return cw2015_write_bytes(REG_CONFIG, &config, 1);
}

// 快速启动
esp_err_t cw2015_quick_start(void)
{
    uint8_t mode = MODE_QUICK_START;
    return cw2015_write_bytes(REG_MODE, &mode, 1);
}

// 电源复位
esp_err_t cw2015_power_reset(void)
{
    uint8_t mode = MODE_RESTART;
    return cw2015_write_bytes(REG_MODE, &mode, 1);
}

// 配置更新函数
static esp_err_t cw2015_update_config_info(void)
{
    uint8_t ret = 0;
    uint8_t i;
    uint8_t reset_val;
    uint8_t reg_val;

    ESP_LOGI(TAG, "开始更新电池配置信息...");
    
    // 检查是否处于睡眠模式
    ret = cw2015_read_bytes(REG_MODE, &reg_val, 1);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "读取模式寄存器失败");
        return ret;
    }
    
    if ((reg_val & MODE_SLEEP_MASK) == MODE_SLEEP) {
        ESP_LOGE(TAG, "设备处于睡眠模式，无法更新配置");
        return ESP_ERR_INVALID_STATE;
    }
    
    // 写入电池配置信息
    for (i = 0; i < SIZE_BATINFO; i++) {
        ret = cw2015_write_bytes(REG_BATINFO + i, (uint8_t*)&cw_bat_config_info[i], 1);
        if (ret != ESP_OK) {
            ESP_LOGE(TAG, "写入配置信息失败，位置: 0x%02X", REG_BATINFO + i);
            return ret;
        }
    }
    
    // 验证写入的数据
    for (i = 0; i < SIZE_BATINFO; i++) {
        ret = cw2015_read_bytes(REG_BATINFO + i, &reg_val, 1);
        if (ret != ESP_OK) {
            ESP_LOGE(TAG, "读取配置信息失败，位置: 0x%02X", REG_BATINFO + i);
            return ret;
        }
        if (reg_val != cw_bat_config_info[i]) {
            ESP_LOGE(TAG, "配置信息验证失败，位置: 0x%02X", REG_BATINFO + i);
            return ESP_ERR_INVALID_CRC;
        }
    }
    
    // 设置配置更新标志
    ret = cw2015_read_bytes(REG_CONFIG, &reg_val, 1);
    if (ret != ESP_OK) {
        return ret;
    }
    
    reg_val |= CONFIG_UPDATE_FLG;   // 设置更新标志
    reg_val &= 0x07;                // 清除 ATHD
    reg_val |= ATHD;                // 设置 ATHD
    
    ret = cw2015_write_bytes(REG_CONFIG, &reg_val, 1);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "设置配置更新标志失败");
        return ret;
    }
    
    // 重启设备
    reset_val = MODE_RESTART;
    ret = cw2015_write_bytes(REG_MODE, &reset_val, 1);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "重启设备失败");
        return ret;
    }
    
    vTaskDelay(pdMS_TO_TICKS(20));
    
    reset_val = MODE_NORMAL;
    ret = cw2015_write_bytes(REG_MODE, &reset_val, 1);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "设置正常模式失败");
        return ret;
    }
    
    ESP_LOGI(TAG, "电池配置信息更新成功");
    return ESP_OK;
}

// 公共函数实现
esp_err_t cw2015_init(void)
{
    uint8_t version;
    uint8_t error_num = 0;
    esp_err_t ret;
    
    ESP_LOGI(TAG, "开始初始化 CW2015...");
    
    // 1. 执行电源复位
    uint8_t mode = MODE_SLEEP;
    ret = cw2015_write_bytes(REG_MODE, &mode, 1);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "电源复位失败");
        return ret;
    }
    vTaskDelay(pdMS_TO_TICKS(20));
    
    // 2. 唤醒设备
    mode = MODE_NORMAL;
    ret = cw2015_write_bytes(REG_MODE, &mode, 1);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "唤醒设备失败");
        return ret;
    }
    vTaskDelay(pdMS_TO_TICKS(10));
    
    // 3. 读取版本号
    while (error_num < 5) {
        ret = cw2015_read_bytes(REG_VERSION, &version, 1);
        if (ret == ESP_OK && version == 0x73) {
            break;
        }
        error_num++;
        vTaskDelay(pdMS_TO_TICKS(100));
    }
    
    if (error_num >= 5) {
        ESP_LOGE(TAG, "版本号验证失败");
        return ESP_ERR_INVALID_VERSION;
    }
    
    // 4. 写入电池建模信息
    ret = cw2015_update_config_info();
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "写入电池建模信息失败: %d", ret);
        return ret;
    }
    
    // 5. 执行快速启动
    mode = MODE_QUICK_START;
    ret = cw2015_write_bytes(REG_MODE, &mode, 1);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "快速启动失败");
        return ret;
    }
    
    // 等待RRT稳定
    vTaskDelay(pdMS_TO_TICKS(100));
    
    // 清除ALRT位
    uint8_t rrt_alert;
    ret = cw2015_read_bytes(REG_RRT_ALERT, &rrt_alert, 1);
    if (ret == ESP_OK) {
        rrt_alert &= 0x7F; // 清除最高位（ALRT位）
        ret = cw2015_write_bytes(REG_RRT_ALERT, &rrt_alert, 1);
        if (ret != ESP_OK) {
            ESP_LOGW(TAG, "清除ALRT位失败");
        }
    }
    
    // 初始化电池信息结构体
    cw_bat.usb_online = 0;
    cw_bat.capacity = 0;
    cw_bat.voltage = 0;
    cw_bat.alt = 0;
    
    ESP_LOGI(TAG, "CW2015 初始化成功");
    return ESP_OK;
} 